#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@File ：UserLogic.py
@Author ：zqy
@Email : zqingy@work@163.com
@note: 用户逻辑
"""
from typing import Optional

from flask import session, g

from application.Parser.UserParser import UserValidator
from application.enumeration.StatusCodeEnum import StatusCodeEnum
from application.exception.BasicException import BasicException
from application.logic import BaseLogic
from application.mapper.UserMapper import UserMapper
from application.model.UserModel import User
from application.util.RedisUtil import RedisUtil
from application.util.StringUtil import (md5_encode, sha1_encode, is_valid_password)
from application.util.TokenUtil import clear_token, generate_token


class UserLogic(BaseLogic):
    """
    用户逻辑层
    """
    model: User = User  # 定义模型
    mapper: UserMapper = UserMapper  # 定义mapper
    # 实例化redis客户端
    redis_client: RedisUtil = RedisUtil()
    validator: UserValidator = UserValidator

    @classmethod
    def now_user_info(cls, user_id: int) -> Optional[dict]:
        """
        获取当前用户信息
        :param user_id: user_id
        :return:
        """
        user_model: Optional[User] = UserMapper.get_info_by_id(model_id=user_id)
        if user_model is None:
            raise BasicException(status_code=StatusCodeEnum.BAD_REQUEST_ERROR.value, error_message="用户不存在")
        user_info: dict = user_model.to_dict()
        user_info.pop("password")  # 删除密码字段
        user_info["roles"] = [i.role.name for i in user_model.roles]  # 添加角色字段
        user_info["addresses"] = [[i.to_dict() for i in user_model.addresses]]
        return user_info

    @classmethod
    def get_list(cls, params: dict) -> dict:
        """
        获取用户信息列表
        :param params
        :return: {
                    items: [...],
                    total, page_size, current_page
                }
        """
        current_page = params.get("current_page", 1)
        page_size = params.get("page_size", 10)
        result: dict = dict(items=[], total=cls.mapper.count(), page_size=page_size, current_page=current_page)
        for user_model in UserMapper.get_info_list(params=params, page_size=page_size, current_page=current_page):
            user_info: dict = user_model.to_dict()
            user_info.pop("password")  # 删除密码字段
            result["items"].append(user_info)  # 添加用户信息到items列表中
        return result

    @classmethod
    def register(cls, params: dict) -> None:
        """
        注册/新增用户
        :param params: 用户信息字典
        :return:
        """
        # 检查用户名是否已存在
        if UserMapper.get_info_by_phone(phone=params.get("phone")):
            raise BasicException(status_code=StatusCodeEnum.ALREADY_EXIST_ERROR.value, error_message="改手机号已注册")
        params["password"] = sha1_encode(text=md5_encode(text=str(params.get("password"))))  # md5 + sha1 加密密码
        user_model: User = User(**params)
        if not UserMapper.insert(model=user_model):
            raise BasicException(status_code=StatusCodeEnum.ERROR.value, error_message="内部错误，请稍后再试")

    @classmethod
    def login(cls, params) -> str:
        """
        登录
        :return: token
        """
        # 检查必填项
        if not all([params.get("username"), params.get("password")]):
            raise BasicException(status_code=StatusCodeEnum.BAD_REQUEST_ERROR.value, error_message="请完善内容")
        # 检查密码是否符合规范
        if not is_valid_password(text=str(params.get("password"))):
            raise BasicException(status_code=StatusCodeEnum.BAD_REQUEST_ERROR.value,
                                 error_message="密码不符合规范（至少一个字母，至少一个数字，至少为6位）")
        user_model: Optional[User] = UserMapper.get_info_by_username(username=params.get("username"))
        # 检查用户是否存在
        if not user_model:
            raise BasicException(status_code=StatusCodeEnum.NOT_FOUND_ERROR.value, error_message="该用户不存在")
        # 检查密码是否正确
        if sha1_encode(text=md5_encode(text=str(params.get("password")))) != user_model.password:
            raise BasicException(status_code=StatusCodeEnum.AUTHORITY_ERROR.value, error_message="密码错误")

        g.user = user_model
        session["user"] = user_model.id  # 保存用户ID到session中
        return generate_token(user_id=user_model.id)

    @classmethod
    def logout(cls) -> None:
        """
        退出登录
        :param user_id: user_id
        :return:
        """
        if not clear_token(user_id=g.user.id):  # 清空token
            raise BasicException(status_code=StatusCodeEnum.BAD_REQUEST_ERROR.value, error_message="用户会话异常")
        session.clear()  # 清空Session
        g.user = None  # 清空g.user

    @classmethod
    def change_password(cls, params) -> None:
        """
        修改密码
        :return:
        """
        user_model: Optional[User] = UserMapper.get_info_by_id(model_id=g.user.id)
        # 检查用户是否存在
        if not user_model:
            raise BasicException(status_code=StatusCodeEnum.NOT_FOUND_ERROR.value, error_message="该用户不存在")
        # 检查密码是否正确
        if user_model.password != sha1_encode(text=md5_encode(text=params["old_password"])):
            raise BasicException(status_code=StatusCodeEnum.AUTHORITY_ERROR.value, error_message="旧密码错误")
        # 修改密码
        if not UserMapper.update_by_id(model_id=g.user.id,
                                       update_dict={
                                           "password": sha1_encode(text=md5_encode(text=params["new_password"]))}):
            raise BasicException(status_code=StatusCodeEnum.ERROR.value, error_message="内部错误，请稍后再试")

    @classmethod
    def update_by_id(cls, _id: int, data: dict) -> None:
        """
        根据ID更新数据
        :param _id:
        :param data: 数据字典
        :return: None
        """
        if _id != g.user.id and not g.user.is_superuser:
            raise BasicException(status_code=StatusCodeEnum.AUTHORITY_ERROR.value, error_message="权限不足")
        cls.mapper.update_by_id(model_id=_id, update_dict=data)
